#include "lemon.h"

#include <algorithm>
#include "symbol.h"
#include "configlist.h"

#if !defined(NDEBUG)
/* explicit instanciation, for debug */
template class std::list<Action*>;
template class std::list<Config*>;
template class std::list<Rule*>;
template class std::vector<Rule*>;
template class std::vector<State*>;
template class std::vector<Symbol*>;
#endif


Lemon::Lemon():
  startRule(0), nxstate(0), nrule(0)
  , nsymbol(0), nterminal(0), errorcnt(0), errsym(0)
  , wildcard(0), name(0),arg(0),tokentype(0)
  ,vartype(0),start(0),stacksize(0),include(0),error(0)
  ,overflow(0),failure(0),accept(0),extracode(0),tokendest(0)
  ,vardest(0),filename(0),outname(0),tokenprefix(0)
  ,nconflict(0),nactiontab(0),tablesize(0),basisflag(0)
  ,has_fallback(0),nolinenosflag(0),argv0(0)
{
  Symbol_new("$");
  errsym = Symbol_new("error");
  errsym->useCnt = 0;
}

/* Compare two states */
int StateKeyEqual::statecmp(const ConfigList& a_list,
                            const ConfigList& b_list) const
{
  int rc;
  auto ita = a_list.begin();
  auto itb = b_list.begin();
  for (rc=0; rc==0 && ita != a_list.end() && itb != b_list.end(); ++ita, ++itb) {
    Config* a = *ita;
    Config* b = *itb;
    rc = a->rp->index - b->rp->index;
    if (rc==0) rc = a->dot - b->dot;
  }
  if (rc==0) {
    if (ita!=a_list.end()) rc = 1;
    if (itb!=b_list.end()) rc = -1;
  }
  return rc;
}

/* Hash a state */
unsigned StateKeyHash::statehash(const ConfigList& a) const
{
  unsigned h=0;
  for (const Config* conf : a) {
    h = h*571 + conf->rp->index*37 + conf->dot;
  }
  return h;
}

int Lemon::AddState(State* data, const ConfigList& key)
{
  if (state_index_.find(key) == state_index_.end()) {
    data->statenum = sorted_states.size(); /* Every state gets a sequence number */
    sorted_states.push_back(data);
    state_index_.insert({key, data->statenum});
  }
}

State* Lemon::FindState(const ConfigList& key)
{
  auto it = state_index_.find(key);
  if (it != state_index_.end()) {
    return sorted_states[it->second];
  }
  return NULL;
}

/* rule-with-code before empty-rule */
void Lemon::SortRules()
{
  /* Assign sequential rule numbers */
  int i = 0;
  for (Rule* rp : this->rules) {
    rp->iRule = rp->code ? i++ : -1;
  }
  for (Rule* rp : this->rules) {
    if (rp->iRule < 0) rp->iRule = i++;
  }
  this->startRule = this->rules.front();
  std::sort(this->rules.begin(), this->rules.end(), [](Rule* a,Rule* b){
      return a->iRule < b->iRule;
    });
}
